﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace KeywordAuction
{
    public partial class SimulatorHostForm : Form
    {
        public AuctionHost AuctionHost { get; set; }
        public IAuctionHostFactory AuctionHostFactory { get; set; }


        public SimulatorHostForm()
        {
            InitializeComponent();
            //AuctionHostFactory = new AuctionFactoryForChapter1();
        }
        private void initializeSimulation()
        {
            AuctionHost = AuctionHostFactory.Create();
            if (string.IsNullOrEmpty(AuctionHost.Name) != true)
            {
                this.Text = "SimulatorHost: " + AuctionHost.Name;
            }
            this.listBoxAdspot.Items.Clear();
            this.listBoxAdvertiser.Items.Clear();
            foreach (var item in AuctionHost.Adspots)
            {
                var adspotLog = new AdspotLog();
                adspotLog.Id = item.Id;
                adspotLog.Name = item.Name;
                this.listBoxAdspot.Items.Add(adspotLog);
            }

            foreach (var item in AuctionHost.Advertisers)
            {
                var advertiserLog = new AdvertiserLog();
                advertiserLog.Id = item.Id;
                advertiserLog.Name = item.Name;
                this.listBoxAdvertiser.Items.Add(advertiserLog);
            }
        }
        private void SimulatorHostForm_Load(object sender, EventArgs e)
        {
            initializeSimulation();
        }

        private void toolStripButtonExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void toolStripButtonSimulate_Click(object sender, EventArgs e)
        {
            initializeSimulation();

            int maxRoundCount = 0;
            if (int.TryParse(this.toolStripTextBoxRound.Text, out maxRoundCount))
            {
                this.toolStrip1.Enabled = false;
                this.toolStrip2.Enabled = false;
                
                this.toolStripProgressBar1.Maximum= maxRoundCount;
                var backGroundWorker = new BackgroundWorker();
                backGroundWorker.WorkerReportsProgress = true;
                backGroundWorker.DoWork += new DoWorkEventHandler(backGroundWorker_DoWork);
                backGroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backGroundWorker_RunWorkerCompleted);
                backGroundWorker.ProgressChanged += new ProgressChangedEventHandler(backGroundWorker_ProgressChanged);
                backGroundWorker.RunWorkerAsync();
            }
        }

        
        void backGroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.toolStripProgressBar1.Value = e.ProgressPercentage;
        }

        void backGroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.toolStrip1.Enabled = true;
            this.toolStrip2.Enabled = true;
            MessageBox.Show("Completed!", "Info", MessageBoxButtons.OK, MessageBoxIcon.Information);
            this.toolStripProgressBar1.Value = 0;
            drawSummaryAdspot();
            drawSummaryAdvertiser();
        }

        private void goNextRound()
        {
            AuctionHost.GoNextRound();

            double totalPayment = 0;
            foreach (var item in AuctionHost.Advertisers)
            {
                var log = this.listBoxAdvertiser.Items.Cast<AdvertiserLog>().Where(p => p.Id == item.Id).FirstOrDefault();
                var newLog = new AdvertiserBidLog { Round = CurrentRound, Strategy = item.CurrentStrategy, Revenue = item.GetValue() };
                foreach (var bid in item.Biddings)
                {
                    newLog.Bids.Add(bid.Bid);
                    int index = bid.AttendingAdspot.GetIndexAdvertiser(bid);
                    if (index < 5)
                    {
                        newLog.AcceptanceList.Add(index);
                    }
                    else
                    {
                        newLog.AcceptanceList.Add(-1);
                    }
                    newLog.Payment = bid.AttendingAdspot.GetPaymentValue(bid.AttendingAdspot.GetIndexAdvertiser(bid)) * bid.AttendingAdspot.Traffic;
                    totalPayment += newLog.Payment;
                }
                log.Log.Add(newLog);
            }

            foreach (var item in AuctionHost.Adspots)
            {
                var log = this.listBoxAdspot.Items.Cast<AdspotLog>().Where(p => p.Id == item.Id).FirstOrDefault();
                var newLog = new BidLog { Round = CurrentRound, Revenue = totalPayment };
                foreach (var bid in item.Bitting)
                {
                    newLog.Log.Add(new AdspotAdvertiserBidLog { AdvertiserId = bid.Advertiser.Id, Value = bid.Bid });
                }
                log.Log.Add(newLog);
            }
            CurrentRound++;

        }

        void backGroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            var worker = sender as BackgroundWorker;
            int maxRoundCount = 0;
            if (int.TryParse(this.toolStripTextBoxRound.Text, out maxRoundCount))
            {
                CurrentRound = 0;
                for (int i = 0; i < maxRoundCount; i++)
                {
                    worker.ReportProgress(i);
                    goNextRound();
                }
            }
        }

        private void toolStripButtonClear_Click(object sender, EventArgs e)
        {
            initializeSimulation();
        }

        private void listBoxAdvertiser_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.listViewAdvertiser.Items.Clear();
            var log = this.listBoxAdvertiser.SelectedItem as AdvertiserLog;
            if (log != null)
            {   //this.listViewAdvertiser.DataBindings = 
                drawChartAdvertiser(log);
                foreach (var item in log.Log)
                {
                    var listViewItem = new ListViewItem();
                    listViewItem.Text = item.Round.ToString();
                    string bidString = "";
                    foreach (var bid in item.Bids)
                    {
                        bidString += bid.ToString() + ",";
                    }
                    listViewItem.SubItems.Add(bidString);
                    listViewItem.SubItems.Add(item.Strategy.ToString());
                    string acceptance = "";
                    foreach (var accept in item.AcceptanceList)
                    {
                        if (accept == -1)
                        {
                            acceptance += "-,";
                        }
                        else
                        {
                            acceptance += accept.ToString() + ",";
                        }
                    }
                    listViewItem.SubItems.Add(acceptance);
                    listViewItem.SubItems.Add(item.Revenue.ToString());
                    listViewItem.SubItems.Add(item.Payment.ToString());
                    this.listViewAdvertiser.Items.Add(listViewItem);
                }
            }
        }
        private void drawSummaryAdvertiser()
        {
            var advertiserLogs = this.listBoxAdvertiser.Items.Cast<AdvertiserLog>();
        
            chartSummaryAdvertiser.Series.Clear();
            chartSummaryAdvertiser.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series { Name = "AverageRevenue", ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line, BorderWidth = 4 });
            chartSummaryAdvertiser.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series { Name = "AveragePayment", ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line, BorderWidth = 4 });
            Dictionary<int, List<double>> RoundAveragePaymentPair = new Dictionary<int, List<double>>();
            Dictionary<int, List<double>> RoundAverageRevenuePair = new Dictionary<int, List<double>>();
            foreach (var item in advertiserLogs)
            {
                foreach (var log in item.Log)
                {
                    if (RoundAverageRevenuePair.ContainsKey(log.Round) != true)
                    {
                        RoundAverageRevenuePair.Add(log.Round, new List<double>());
                    }
                    RoundAverageRevenuePair[log.Round].Add(log.Revenue);

                    if (RoundAveragePaymentPair.ContainsKey(log.Round) != true)
                    {
                        RoundAveragePaymentPair.Add(log.Round, new List<double>());
                    }
                    RoundAveragePaymentPair[log.Round].Add(log.Payment);
                }
            }

            foreach (var item in RoundAveragePaymentPair)
            {
                chartSummaryAdvertiser.Series[1].Points.AddXY(item.Key, item.Value.Average(p => p));
            }
            foreach (var item in RoundAverageRevenuePair)
            {
                chartSummaryAdvertiser.Series[0].Points.AddXY(item.Key, item.Value.Average(p => p));
            }
        }
        private void drawSummaryAdspot()
        {
            var adspotLogs = this.listBoxAdspot.Items.Cast<AdspotLog>();
            this.chartSummaryAdspot.Series.Clear();
            this.chartSummaryAdspot.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series { Name = "AverageHostRevenue", ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line, BorderWidth = 4 });
            chartSummaryAdspot.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series { Name = "AverageBid", ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point });
            Dictionary<int, List<double>> RoundAverageBidPair = new Dictionary<int, List<double>>();
            Dictionary<int, List<double>> RoundAverageRevenuePair = new Dictionary<int, List<double>>();

            foreach (var item in adspotLogs)
            {
                foreach (var log in item.Log)
                {
                    if (RoundAverageRevenuePair.ContainsKey(log.Round) != true)
                    {
                        RoundAverageRevenuePair.Add(log.Round, new List<double>());
                    }
                    RoundAverageRevenuePair[log.Round].Add(log.Revenue);

                    if (RoundAverageBidPair.ContainsKey(log.Round) != true)
                    {
                        RoundAverageBidPair.Add(log.Round, new List<double>());
                    }
                    RoundAverageBidPair[log.Round].Add(log.Log.Average(p=>p.Value));
                }
            }
            foreach (var item in RoundAverageBidPair)
            {
                chartSummaryAdspot.Series[1].Points.AddXY(item.Key, item.Value.Average(p => p));
            }
            foreach (var item in RoundAverageRevenuePair)
            {
                chartSummaryAdspot.Series[0].Points.AddXY(item.Key, item.Value.Average(p => p));
            }
        }

        private void drawChartAdvertiser(AdvertiserLog log)
        {
            chartAdvertiser.Series.Clear();
            chartAdvertiser.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series { Name = "Revenue", ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line, BorderWidth = 4 });
            chartAdvertiser.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series { Name = "Payment", ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line , BorderWidth =4 });
            var advertiser = AuctionHost.Advertisers.Where(p=>p.Id == log.Id).FirstOrDefault();
          
            
            for (int i = 0; i < advertiser.Biddings.Count; i++)
            {
                var bidding = advertiser.Biddings.Where(p => p.AttendingAdspot == AuctionHost.Adspots[i]).FirstOrDefault();
                chartAdvertiser.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series
                {
                    Name = string.Format("{0}(RPC：{1})", AuctionHost.Adspots[i].Name, bidding.ExpectedRevenue),
                    ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line
                }); ;
            }
            var logData = log.Log.FirstOrDefault();
            if (logData != null)
            {
           
                foreach (var item in log.Log)
                {
                    chartAdvertiser.Series[0].Points.AddXY(item.Round, item.Revenue);
                    chartAdvertiser.Series[1].Points.AddXY(item.Round, item.Payment);

                    for (int i = 0; i < item.Bids.Count; i++)
                    {
                        chartAdvertiser.Series[i + 2].Points.AddXY(item.Round, item.Bids[i]);

                    }
                }
            }
        }


        private void listBoxAdspot_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.listViewAdspot.Items.Clear();
            var log = this.listBoxAdspot.SelectedItem as AdspotLog;
            if (log != null)
            {
                drawChartAdspot(log);

                this.listBoxCTR.Items.Clear();
                var adspot = AuctionHost.Adspots.Where(p=>p.Id == log.Id).FirstOrDefault();
                foreach (var item in adspot.ClickThroughtRates)
                {
                    this.listBoxCTR.Items.Add(item);
                }
                foreach (var item in log.Log)
                {
                    var listViewItem = new ListViewItem();
                    listViewItem.Text = item.Round.ToString();
                 
                    listViewItem.SubItems.Add(item.Revenue.ToString());
                    listViewItem.SubItems.Add(item.Log.Average(p=>p.Value).ToString());
                    this.listViewAdspot.Items.Add(listViewItem);
                }
            }
        }

        private void drawChartAdspot(AdspotLog log)
        {
            chartAdspot.Series.Clear();
            chartAdspot.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series { Name = "HostRevenue", ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Line, BorderWidth = 4 });
            chartAdspot.Series.Add(new System.Windows.Forms.DataVisualization.Charting.Series { Name = "Bid", ChartType = System.Windows.Forms.DataVisualization.Charting.SeriesChartType.Point});
            foreach (var item in log.Log)
            {
                foreach (var bid in item.Log)
	            {
                    chartAdspot.Series[1].Points.AddXY(item.Round, bid.Value);
                }
                chartAdspot.Series[0].Points.AddXY(item.Round, item.Revenue);
            }
        }

        public int CurrentRound { get; set; }
        private void toolStripButtonNextRound_Click(object sender, EventArgs e)
        {
            goNextRound();
        }

        private void buttonRefresh_Click(object sender, EventArgs e)
        {
            drawSummaryAdspot();
            drawSummaryAdvertiser();
        }

        private void toolStripButtonExport_Click(object sender, EventArgs e)
        {
            var exporter = new Utility.ExcelExporterUtility();
            exporter.Export(this.listBoxAdspot.Items.Cast<AdspotLog>(), this.listBoxAdvertiser.Items.Cast<AdvertiserLog>());
        }
    }
}
